package cn.elead.it.sso.server.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.gitee.elead.api.ApiAssert;
import com.gitee.elead.api.emuns.ErrorCodeEnum;
import com.gitee.elead.web.api.ApiResponses;
import com.gitee.elead.web.controller.SuperController;

import cn.elead.it.sso.core.constant.GlobalVariable;
import cn.elead.it.sso.core.login.SsoTokenLoginHelper;
import cn.elead.it.sso.core.login.SsoWebLoginHelper;
import cn.elead.it.sso.core.model.SsoUser;
import cn.elead.it.sso.core.store.SsoSessionIdHelper;
import cn.elead.it.sso.core.util.CookieUtil;
import cn.elead.it.sso.core.util.JWTUtils;
import cn.elead.it.sso.core.util.JedisUtil;
import cn.elead.it.sso.core.util.RSAUtil;
import cn.elead.it.sso.server.oauth.param.OauthAuthorizeParam;
import cn.elead.it.sso.server.oauth.param.OauthFormLoginParam;
import cn.elead.it.sso.system.emuns.UserStatusEnum;
import cn.elead.it.sso.system.model.Client;
import cn.elead.it.sso.system.model.User;
import cn.elead.it.sso.system.service.IClientService;
import cn.elead.it.sso.system.service.IUserService;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;

/**
 * Oauth单点登录(前后端分离)
 * 
 * @author luopeng
 *
 */
@Controller
@RequestMapping("/oauth")
public class OauthController extends SuperController {
	
	@Value("${ras.privateKey}")
	private String privateKey;
	
	@Autowired
	private IUserService userService;

	@Autowired
	private IClientService clientService;

	/**
	 * http://ssoserver.com:8100/sso-server/oauth/authorize?response_type=code&client_id=elead_learning&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2FcodeCallback%3Fredirect_uri%3Dhttp%253A%252F%252Flocalhost%253A8000%252FTKeyClient
	 * 
	 * 登录页面入口
	 */
	@GetMapping(value = "/authorize")
	public String authorize(ModelMap model, OauthAuthorizeParam oAuthAuthorizeParam) {

		// 获取客户端信息
		Client client = clientService.findByClientId(oAuthAuthorizeParam.getClientId());
		if (ObjectUtil.isNull(client)) {
			// 进入错误页面
			model.addAttribute("errorMsg", "您好,请先注册单点客户端信息！");
			return GlobalVariable.DEFAULT_ERROR_PAGE_PATH;
		}

		// 退出
		if (StrUtil.isNotBlank(oAuthAuthorizeParam.getSessionId())) {
			// logout, remove storeKey
			SsoTokenLoginHelper.logout(request, response, oAuthAuthorizeParam.getSessionId());
			model.addAttribute(GlobalVariable.REDIRECT_URI, request.getParameter(GlobalVariable.REDIRECT_URI));
			model.addAttribute(GlobalVariable.DEFAULT_LOGIN_PAGE_CLIENT_INFO_KEY, client);
			// 进入登录页面
			return GlobalVariable.THEME + GlobalVariable.DEFAULT_LOGIN_PAGE_PATH;
		}

		// 校验当前是否已经登录
		SsoUser ssoUser = SsoWebLoginHelper.loginCheck(request, response);
		if (ObjectUtil.isNull(ssoUser)) {
			model.addAttribute("errorMsg", request.getParameter("errorMsg"));
			model.addAttribute(GlobalVariable.REDIRECT_URI, request.getParameter(GlobalVariable.REDIRECT_URI));
			model.addAttribute(GlobalVariable.DEFAULT_LOGIN_PAGE_CLIENT_INFO_KEY, client);
			// 没有登录,进入登录页面
			return GlobalVariable.THEME + GlobalVariable.DEFAULT_LOGIN_PAGE_PATH;
		} else {
			String redirectUrl = getRedirectUrlWithCode(oAuthAuthorizeParam.getRedirectUri(), oAuthAuthorizeParam.getState(), ssoUser, client);
			return GlobalVariable.REDIRECT_URI_PREFIX + redirectUrl;
		}
	}

	/**
	 * 表单登录接口：验证用户名和密码
	 * @throws Exception 
	 */
	@PostMapping(value = "/authorize")
	public String formLogin(RedirectAttributes redirectAttributes, OauthFormLoginParam oauthFormLoginParam) throws Exception {

		// 获取客户端信息
		Client client = clientService.findByClientId(oauthFormLoginParam.getClientId());
		if (ObjectUtil.isNull(client)) {
			// 进入错误页面
			redirectAttributes.addAttribute("errorMsg", "您好,请先注册单点客户端信息！");
			return GlobalVariable.DEFAULT_ERROR_PAGE_PATH;
		}
		String username = oauthFormLoginParam.getUsername();
		String password = oauthFormLoginParam.getPassword();

		// valid login
		User user = userService.findUser(username);
		if (ObjectUtil.isNull(user)) {
			return redirectLogin(redirectAttributes, client, "用户不存在");
		}
		password = RSAUtil.encryptByPrivateKey(password, privateKey);
		if (!password.equals(user.getPassword())) {
			return redirectLogin(redirectAttributes, client, "用户名密码错误");
		}
		if (UserStatusEnum.NORMAL.equals(user.getStatus())) {
			return redirectLogin(redirectAttributes, client, "用户被禁用");
		}

		String redirectUrl = getRedirectUrlWithCode(oauthFormLoginParam.getRedirectUri(), oauthFormLoginParam.getState(), new SsoUser().setUserId(user.getId()).setUserName(user.getUserName()),
				client);

		return GlobalVariable.REDIRECT_URI_PREFIX + redirectUrl;

	}

	/**
	 * Logout
	 *
	 * @param sessionId
	 * @return
	 */
	@RequestMapping("/logout")
	public String logout(RedirectAttributes redirectAttributes, OauthAuthorizeParam oAuthAuthorizeParam) {

		// 获取客户端信息
		Client client = clientService.findByClientId(oAuthAuthorizeParam.getClientId());
		if (ObjectUtil.isNull(client)) {
			// 进入错误页面
			redirectAttributes.addAttribute("errorMsg", "您好,请先注册单点客户端信息！");
			return GlobalVariable.DEFAULT_ERROR_PAGE_PATH;
		}

		// logout, remove storeKey
		SsoTokenLoginHelper.logout(request, response, oAuthAuthorizeParam.getSessionId());

		redirectAttributes.addAttribute(GlobalVariable.REDIRECT_URI, request.getParameter(GlobalVariable.REDIRECT_URI));
		return GlobalVariable.REDIRECT_URI_PREFIX + GlobalVariable.SSO_LOGIN;
	}

	/**
	 * logincheck
	 *
	 * @param sessionId
	 * @return
	 */
	@RequestMapping("/logincheck")
	@ResponseBody
	public ApiResponses<SsoUser> logincheck(String sessionId) {
		// logout
		SsoUser ssoUser = SsoTokenLoginHelper.loginCheck(sessionId);

		ApiAssert.notNull(ErrorCodeEnum.UNAUTHORIZED, ssoUser);

		return success(ssoUser);
	}

	/**
	 * 重定向到登录页面
	 * @param redirectAttributes
	 * @param client
	 * @param errorMsg
	 * @return
	 */
	private String redirectLogin(RedirectAttributes redirectAttributes, Client client, String errorMsg) {
		redirectAttributes.addAttribute("client_id", client.getClientId());
		redirectAttributes.addAttribute("errorMsg", errorMsg);
		redirectAttributes.addAttribute(GlobalVariable.REDIRECT_URI, request.getParameter(GlobalVariable.REDIRECT_URI));
		return GlobalVariable.REDIRECT_URI_PREFIX + GlobalVariable.SSO_LOGIN;
	}

	private String getRedirectUrlWithCode(String redirectUri, String state, SsoUser user, Client client) {

		// 1、make sso user
		SsoUser ssoUser = new SsoUser().setUserId(user.getUserId()).setUserName(user.getUserName()).setClientSecret(client.getClientSecret()).setVersion(IdUtil.simpleUUID());
		// 2、make session id
		String sessionId = SsoSessionIdHelper.makeSessionId(ssoUser);
		// 2、make code
		String code = JWTUtils.generate(sessionId);
		// code有效2分钟
		JedisUtil.setObjectValue(code, ssoUser, 2 * 60);
		// 4.将session添加到Cookie
		CookieUtil.set(response, GlobalVariable.SSO_SESSIONID, JWTUtils.generate(code), false);

		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.append(redirectUri);
		if (StrUtil.containsIgnoreCase(redirectUri, "?")) {
			stringBuilder.append("&");
		} else {
			stringBuilder.append("?");
		}
		stringBuilder.append(GlobalVariable.OAUTH_CODE_RESPONSE_TYPE);
		stringBuilder.append("=");
		stringBuilder.append(code);
		if (StrUtil.isNotBlank(state)) {
			stringBuilder.append("&");
			stringBuilder.append(GlobalVariable.OAUTH_STATE_KEY);
			stringBuilder.append("=");
			stringBuilder.append(state);
		}

		return stringBuilder.toString();
	}

}